package com.hzw.saas.web.admin.project.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.flow.pojo.bo.FlowProcessRecordBO;
import com.hzw.saas.common.flow.pojo.data.UserInfo;
import com.hzw.saas.common.flow.pojo.enums.FlowNodeStatus;
import com.hzw.saas.common.flow.pojo.enums.FlowStatus;
import com.hzw.saas.common.flow.pojo.model.FlowInstance;
import com.hzw.saas.common.flow.pojo.model.FlowNode;
import com.hzw.saas.common.flow.pojo.model.FlowProcess;
import com.hzw.saas.common.flow.service.IFlowInstanceService;
import com.hzw.saas.common.flow.service.IFlowNodeService;
import com.hzw.saas.common.flow.service.IFlowProcessRecordService;
import com.hzw.saas.common.flow.service.IFlowProcessService;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.enums.IsEnum;
import com.hzw.saas.service.project.bo.ProjectApplyBO;
import com.hzw.saas.service.project.bo.ProjectApplyInfoBO;
import com.hzw.saas.service.project.bo.ProjectAttachmentBO;
import com.hzw.saas.service.project.enums.AttachmentType;
import com.hzw.saas.service.project.model.ProjectApply;
import com.hzw.saas.service.project.service.IProjectApplyService;
import com.hzw.saas.service.project.service.IProjectAttachmentService;
import com.hzw.saas.web.admin.project.dto.ProjectApplyDetail;
import com.hzw.saas.web.admin.project.dto.ProjectApplyInfoDTO;
import com.hzw.saas.web.admin.project.dto.ProjectApplyOperator;
import com.hzw.saas.web.admin.project.dto.ProjectApplyStatus;
import com.hzw.saas.web.admin.project.param.DoProcessParam;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Description
 * @Date 2021/8/9 3:40 下午
 * @Created by sonam
 */
@RestController
@Api(tags = "项目管理/项目申请")
@RequiredArgsConstructor
@RequestMapping("/project/apply")
public class ProjectApplyController {
    /** 鸿之微项目审批流程ID */
    private final static String HZW_PROJECT_APPLY_FLOW_ID = "1";

    private final IProjectApplyService projectApplyService;
    private final IProjectAttachmentService projectAttachmentService;
    private final IFlowProcessService flowProcessService;
    private final IFlowInstanceService flowInstanceService;
    private final IFlowProcessRecordService flowProcessRecordService;
    private final IFlowNodeService flowNodeService;

    @ApiOperation(value = "获取项目申请所有状态列表")
    @ApiOperationSort(0)
    @GetMapping("/status")
    public ResponseEntity<List<ProjectApplyStatus>> statusList() {
        List<FlowNode> flowNodes = flowNodeService.lambdaQuery().select(FlowNode::getPid, FlowNode::getFlowNodeText)
            .eq(FlowNode::getFlowId, HZW_PROJECT_APPLY_FLOW_ID)
            .list();
        return ResponseEntity.ok(buildStatus(flowNodes));
    }

    @ApiOperation(value = "获取审核中的状态列表")
    @ApiOperationSort(0)
    @GetMapping("/process/status")
    public ResponseEntity<List<ProjectApplyStatus>> processStatusList() {
        List<FlowNode> flowNodes = flowNodeService.lambdaQuery().select(FlowNode::getPid, FlowNode::getFlowNodeText)
            .eq(FlowNode::getFlowId, HZW_PROJECT_APPLY_FLOW_ID)
            .ne(FlowNode::getFlowNodeStatus, FlowNodeStatus.END_NODE.code()).list();
        return ResponseEntity.ok(buildStatus(flowNodes));
    }

    @ApiOperation(value = "获取审核完成状态列表")
    @ApiOperationSort(1)
    @GetMapping("/complete/status")
    public ResponseEntity<List<ProjectApplyStatus>> completeStatusList() {
        List<FlowNode> flowNodes = flowNodeService.lambdaQuery().select(FlowNode::getPid, FlowNode::getFlowNodeText)
            .eq(FlowNode::getFlowId, HZW_PROJECT_APPLY_FLOW_ID)
            .eq(FlowNode::getFlowNodeStatus, FlowNodeStatus.END_NODE.code()).list();
        return ResponseEntity.ok(buildStatus(flowNodes));
    }

    private List<ProjectApplyStatus> buildStatus(List<FlowNode> flowNodes) {
        if (CollectionUtil.isEmpty(flowNodes)) {
            return new ArrayList<>();
        }
        List<ProjectApplyStatus> projectApplyStatuses = new ArrayList<>();
        flowNodes.forEach(flowNode -> {
            ProjectApplyStatus projectApplyStatus = new ProjectApplyStatus();
            projectApplyStatus.setStatusId(flowNode.getPid());
            projectApplyStatus.setStatusText(flowNode.getFlowNodeText());
            projectApplyStatuses.add(projectApplyStatus);
        });
        return projectApplyStatuses;
    }

    @ApiOperation(value = "获取项目申请列表")
    @ApiOperationSort(2)
    @GetMapping("/")
    public ResponseEntity<IPage<ProjectApplyInfoDTO>> listProjectApply(PageParam pageParam,
                                                                       @RequestParam(name = "fuzzy", required = false) @ApiParam(value = "模糊检索条件，用户名，电话，邮箱，项目名称，研究方向，流程名称，单位名称") String fuzzy,
                                                                       @RequestParam(name = "type", required = false) @ApiParam(value = "审批状态,0-项目申请待审批,1-项目申请已审批,2-项目验收待审批,3-项目验收已审批") Integer type,
                                                                       @RequestParam(name = "notifyState", required = false) @ApiParam(value = "通知状态,0-未通知,1-已通知") Integer notifyState,
                                                                       @RequestParam(name = "statusIds", required = false) @ApiParam(value = "状态ID") List<String> statusIds,
                                                                       @RequestParam(name = "levelIds", required = false) @ApiParam(value = "等级ID") List<String> levelIds,
                                                                       @RequestParam(name = "sort", required = false) @ApiParam(value = "申请时间排序,1-降序,0-升序") Integer sort) {
        IPage<ProjectApplyInfoBO> projectApplyInfoBOIPage = projectApplyService.pageProjectApply(pageParam, HZW_PROJECT_APPLY_FLOW_ID, fuzzy, type, statusIds, notifyState, levelIds, sort);
        IPage<ProjectApplyInfoDTO> projectApplyInfoDTOIPage = PageUtils.convert(projectApplyInfoBOIPage, ProjectApplyInfoDTO.class);
        projectApplyInfoDTOIPage.getRecords().forEach(record -> {
            // 设置通知状态
            record.setNotifyStateText(record.getNotifyState() == 1 ? "已通知" : "未通知");

            // 判断是否有审批操作
            String flowInstanceId = record.getFlowInstanceId();
            FlowInstance flowInstance = flowInstanceService.getById(flowInstanceId);
            FlowStatus flowStatus = FlowStatus.instance(flowInstance.getState());
            if (flowStatus == FlowStatus.COMPLETE) {
                return;
            }
            List<FlowProcess> flowProcesses = flowProcessService.listNextFlowProcesses(flowInstance,
                new UserInfo().setUserId(SecurityUtils.getUser().getUserId()), IsEnum.TRUE.getCode());
            if (CollectionUtil.isEmpty(flowProcesses)) {
                return;
            }
            // 获取审批操作
            List<ProjectApplyOperator> projectApplyOperators = new ArrayList<>();
            record.setProjectApplyOperators(projectApplyOperators);
            flowProcesses.forEach(flowProcess -> {
                ProjectApplyOperator projectApplyOperator = new ProjectApplyOperator();
                projectApplyOperator.setFlowProcessId(flowProcess.getPid());
                projectApplyOperator.setOperatorName(flowProcess.getFlowProcessName());
                projectApplyOperators.add(projectApplyOperator);
            });
        });
        return ResponseEntity.ok(projectApplyInfoDTOIPage);
    }

    @ApiOperation(value = "项目详细信息")
    @ApiOperationSort(3)
    @GetMapping("/detail/{projectApplyId}")
    public ResponseEntity<ProjectApplyDetail> getProjectApplyTaskList(@PathVariable String projectApplyId) {
        ProjectApplyBO projectApply = projectApplyService.getProjectApply(null, projectApplyId);
        ProjectApplyDetail projectApplyDetail = MapperUtil.nf().map(projectApply, ProjectApplyDetail.class);
        List<FlowProcessRecordBO> flowProcesses = flowProcessRecordService.listRecordBOs(projectApply.getFlowInstanceId());
        projectApplyDetail.setFlowProcesses(flowProcesses);
        return ResponseEntity.ok(projectApplyDetail);
    }

    @GetMapping("/{flowInstanceId}/process")
    @ApiOperation(value = "获取项目审批操作")
    @ApiOperationSort(4)
    @ApiResponses({
        @ApiResponse(code = 202, message = "审批流程已完成")
    })
    public ResponseEntity<List<ProjectApplyOperator>> listProjectApplyOperation(@PathVariable @ApiParam("流程实例ID") String flowInstanceId) {
        FlowInstance flowInstance = flowInstanceService.getById(flowInstanceId);
        FlowStatus flowStatus = FlowStatus.instance(flowInstance.getState());
        AssertUtil.assertThrow("审批流程已完成", HttpStatus.ACCEPTED, flowStatus == FlowStatus.COMPLETE);
        List<FlowProcess> flowProcesses = flowProcessService.listNextFlowProcesses(flowInstance,
            new UserInfo().setUserId(SecurityUtils.getUser().getUserId()), IsEnum.TRUE.getCode());
        if (CollectionUtil.isEmpty(flowProcesses)) {
            return null;
        }
        List<ProjectApplyOperator> projectApplyOperators = new ArrayList<>();
        flowProcesses.forEach(flowProcess -> {
            ProjectApplyOperator projectApplyOperator = new ProjectApplyOperator();
            projectApplyOperator.setFlowProcessId(flowProcess.getPid());
            projectApplyOperator.setOperatorName(flowProcess.getFlowProcessName());
            projectApplyOperators.add(projectApplyOperator);
        });
        return ResponseEntity.ok(projectApplyOperators);
    }

    @PostMapping("/process")
    @ApiOperation(value = "审批处理")
    @ApiOperationSort(5)
    @ApiResponses({
        @ApiResponse(code = 200, message = "审批处理成功"),
        @ApiResponse(code = 403, message = "审批流程没有权限"),
        @ApiResponse(code = 404, message = "审批流程丢失"),
        @ApiResponse(code = 500, message = "审批流程内部错误"),

    })
    public ResponseEntity<Void> operationProjectApply(@RequestBody @Validated DoProcessParam processParam) {
        flowInstanceService.doFlowProcess(processParam.getFlowInstanceId(), processParam.getFlowProcessId(), SecurityUtils.getUser().getUserId(), processParam.getSuggestion());
        return ResponseEntity.ok().build();
    }

    @GetMapping("/{flowInstanceId}/status")
    @ApiOperation(value = "获取项目审批状态")
    @ApiOperationSort(6)
    public ResponseEntity<ProjectApplyStatus> getProjectApplyStatus(@PathVariable @ApiParam("流程实例ID") String flowInstanceId) {
        FlowInstance flowInstance = flowInstanceService.getById(flowInstanceId);
        ProjectApplyStatus projectApplyStatus = new ProjectApplyStatus();
        if (Objects.nonNull(flowInstance)) {
            String flowNodeId = flowInstance.getFlowNodeId();
            FlowNode flowNode = flowNodeService.getById(flowNodeId);
            projectApplyStatus.setStatusId(flowNode.getPid());
            projectApplyStatus.setStatusText(flowNode.getFlowNodeName());
        }
        return ResponseEntity.ok(projectApplyStatus);
    }

    @GetMapping(value = "/{flowInstanceId}/export/pdf")
    @SysLog(operation = "项目申请导出PDF", mode = 3)
    @ApiOperation(value = "项目申请导出PDF", notes = "项目申请导出PDF")
    @ApiOperationSort(6)
    public void projectApplyExportPDF(@PathVariable @ApiParam("项目申请ID") String flowInstanceId, HttpServletResponse response) {
        projectApplyService.projectApplyExportPDF(flowInstanceId, response, true);
    }

    @ApiOperationSort(7)
    @PutMapping("/notify/{projectApplyId}")
    @SysLog(operation = "项目申请通知", mode = 3)
    @ApiOperation(value = "项目申请通知", notes = "项目申请通知")
    public void projectApplyNotify(@PathVariable @ApiParam("项目申请ID") String projectApplyId) {
        AssertUtil.assertThrow("项目通知失败，项目申请不存在", projectApplyService.lambdaQuery().eq(ProjectApply::getPid, projectApplyId).count() <= 0);
        ProjectApply projectApply = new ProjectApply();
        projectApply.setPid(projectApplyId);
        projectApply.setNotifyState(1); // 设置发送邮件通知状态
        projectApplyService.updateById(projectApply);
    }

    @GetMapping(value = "/{pid}/attachments")
    @SysLog(operation = "获取附件列表")
    @ApiOperation(value = "获取附件列表", notes = "获取附件列表")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "pid", value = "项目申请ID", paramType = "path", dataType = "String", required = true),
        @ApiImplicitParam(name = "attachmentType", value = "附件类型，" + AttachmentType.API_TEXT, paramType = "query", dataType = "int", allowMultiple = true, required = true),
    })
    @ApiOperationSort(22)
    public ResponseEntity<List<ProjectAttachmentBO>> listAttachments(@PathVariable String pid, Integer[] attachmentType) {
        List<ProjectAttachmentBO> attachmentBOS = projectAttachmentService.listAttachmentBo(pid, attachmentType);
        return ResponseEntity.ok(attachmentBOS);
    }

}
